import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.swing.InputMap;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class QuiverFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	private Configuration config;
	private static QuiverFrame instance;
	public JTabbedPane tabs;
	public GAPInterface gapInterface;

	private QuiverFrame() {
		config = Configuration.getDefaultConfiguration();

		setJMenuBar(createMenu());
		tabs = createTabbedPane();
		add(tabs);

		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setSize((int) config.windowWidth, (int) config.windowHeight);
		setTitle(config.windowTitle);
		setVisible(true);
	}

	public static QuiverFrame getInstance() {
		if (instance == null) {
			instance = new QuiverFrame();
		}
		return instance;
	}

	// should subclass JTabbedPane
	private JTabbedPane createTabbedPane() {
		final JTabbedPane tabs = new JTabbedPane();
		tabs.setFocusTraversalKeysEnabled(false);
		InputMap im = tabs.getInputMap(JTabbedPane.WHEN_IN_FOCUSED_WINDOW);
		im.put(config.nextQuiverKey, "navigateRight");
		im.put(config.prevQuiverKey, "navigateLeft");

		tabs.addChangeListener(new ChangeListener() {

			@Override
			public void stateChanged(ChangeEvent arg0) {
				if (instance == null) {
					return;
				}
				QuiverPanel panel = instance.getActivePanel();
				if (panel == null) {
					return;
				}
				Actions.undoAction.setEnabled(panel.canUndo());
				Actions.redoAction.setEnabled(panel.canRedo());
			}
		});

		tabs.addMouseListener(new MouseListener() {

			@Override
			public void mouseClicked(MouseEvent e) {
				if (e.getButton() != e.BUTTON3) {
					return;
				}
				int index = tabs.indexAtLocation(e.getX(), e.getY());
				if (index == -1) {
					return;
				}
				RepresentationSelection reprSelection = new RepresentationSelection(
						getActivePanel());
				reprSelection.show(tabs, e.getX(), e.getY());
			}

			@Override
			public void mouseEntered(MouseEvent arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mouseExited(MouseEvent arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mousePressed(MouseEvent arg0) {
				// TODO Auto-generated method stub

			}

			@Override
			public void mouseReleased(MouseEvent arg0) {
				// TODO Auto-generated method stub

			}

		});
		
		return tabs;
	}

	public QuiverPanel getActivePanel() {
		return (QuiverPanel) tabs.getSelectedComponent();
	}

	public void renameActivePanel(String newName) {
		QuiverPanel activePanel = getActivePanel();
		activePanel.quiver.setName(newName);
		tabs.setTitleAt(tabs.getSelectedIndex(), activePanel.quiver.getName());
	}

	private JMenu createEditMenu() {
		JMenu editMenu = new JMenu("Edit");
		editMenu.setMnemonic(KeyEvent.VK_E);
		JMenuItem undoItem = new JMenuItem(Actions.undoAction);
		undoItem.setAccelerator(config.undoKey);
		editMenu.add(undoItem);
		JMenuItem redoItem = new JMenuItem(Actions.redoAction);
		redoItem.setAccelerator(config.redoKey);
		editMenu.add(redoItem);
		return editMenu;
	}

	private JMenu createQuiversMenu() {
		JMenu quiverMenu = new JMenu("Quiver");
		quiverMenu.setMnemonic(KeyEvent.VK_Q);
		JMenuItem newQuiverItem = new JMenuItem(Actions.newQuiverAction);
		newQuiverItem.setAccelerator(config.newQuiverKey);
		quiverMenu.add(newQuiverItem);
		JMenu loadMenu = new JMenu("Load");
		loadMenu.setMnemonic(KeyEvent.VK_L);
		JMenu standardQuiversMenu = new JMenu("Standard quivers");
		standardQuiversMenu.setMnemonic(KeyEvent.VK_S);
		standardQuiversMenu.add(new JMenuItem(Actions.loadAnAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadDnAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadEnAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadCycleAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadWheelAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadStarAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadFriendshipAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadCompleteAction));
		standardQuiversMenu.add(new JMenuItem(Actions.loadPyramidAction));
		loadMenu.add(standardQuiversMenu);
		quiverMenu.add(loadMenu);
		JMenuItem renameQuiverItem = new JMenuItem(Actions.renameAction);
		renameQuiverItem.setAccelerator(config.renameQuiverKey);
		quiverMenu.add(renameQuiverItem);
		JMenuItem closeQuiverItem = new JMenuItem(Actions.closeQuiverAction);
		closeQuiverItem.setAccelerator(config.closeQuiverKey);
		quiverMenu.add(closeQuiverItem);
		JMenuItem clearItem = new JMenuItem(Actions.clearAction);
		clearItem.setAccelerator(config.clearQuiverKey);
		quiverMenu.add(clearItem);
		JMenuItem snapItem = new JMenuItem(Actions.snapAction);
		snapItem.setAccelerator(config.snapKey);
		quiverMenu.add(snapItem);
		JMenuItem arrangeItem = new JMenuItem(Actions.arrangeAction);
		arrangeItem.setAccelerator(config.arrangeKey);
		quiverMenu.add(arrangeItem);
		return quiverMenu;
	}

	private JMenu createRepresentationsMenu() {
		JMenu representationMenu = new JMenu("Representation");
		representationMenu.add(new JMenuItem(Actions.newRepresentationAction));
		return representationMenu;
	}

	private JMenu createGAPMenu() {
		JMenu gapMenu = new JMenu("GAP");
		gapMenu.setMnemonic(KeyEvent.VK_G);
		gapMenu.add(new JMenuItem(Actions.startGAPAction));
		gapMenu.add(new JMenuItem(Actions.saveGAPSessionAction));
		gapMenu.add(new JMenuItem(Actions.showGAPInterfaceAction));
		gapMenu.add(new JMenuItem(Actions.quiverProductGAPAction));
		gapMenu.add(new JMenuItem(Actions.sendQuiversGAPAction));
		return gapMenu;
	}

	private JMenu createOptionsMenu() {
		JMenu optionsMenu = new JMenu("Options");
		optionsMenu.setMnemonic(KeyEvent.VK_O);
		JCheckBoxMenuItem toggleGridItem = new JCheckBoxMenuItem(
				Actions.toggleGridAction);
		toggleGridItem.setSelected(config.gridVisible);
		optionsMenu.add(toggleGridItem);
		JCheckBoxMenuItem toggleLabelItem = new JCheckBoxMenuItem(
				Actions.toggleLabelAction);
		toggleLabelItem.setSelected(config.showLabels);
		optionsMenu.add(toggleLabelItem);
		JCheckBoxMenuItem autoArrangeItem = new JCheckBoxMenuItem(
				Actions.autoArrangeAction);
		autoArrangeItem.setSelected(config.autoArrangeQuiver);
		optionsMenu.add(autoArrangeItem);
		return optionsMenu;
	}

	private JMenuBar createMenu() {
		JMenuBar menuBar = new JMenuBar();
		menuBar.add(createEditMenu());
		menuBar.add(createQuiversMenu());
		menuBar.add(createRepresentationsMenu());
		menuBar.add(createGAPMenu());
		menuBar.add(createOptionsMenu());
		return menuBar;
	}

	public void addTab(Quiver quiver, boolean active) {
		QuiverPanel panel = new QuiverPanel(quiver);
		tabs.addTab(quiver.getName(), panel);
		if (active) {
			tabs.setSelectedIndex(tabs.getTabCount() - 1);
		}
	}

	public void addTab(boolean active) {
		Quiver quiver = new Quiver();
		addTab(quiver, active);
	}

	public void closeTab() {
		tabs.remove(tabs.getSelectedIndex());
		if (tabs.getTabCount() == 0) {
			addTab(true);
		}
	}

	public ArrayList<Quiver> getQuivers() {
		ArrayList<Quiver> quivers = new ArrayList<Quiver>();
		for (Component c : tabs.getComponents()) {
			QuiverPanel panel = (QuiverPanel) c;
			quivers.add(panel.quiver);
		}
		return quivers;
	}

	public Set<String> getNamePool() {
		Set<String> pool = new HashSet<String>();
		QuiverPanel panel = getActivePanel();
		Quiver quiver = panel.quiver;
		for (Arrow arrow : quiver.getArrows()) {
			pool.add(arrow.getName());
		}
		for (Node node : quiver.getNodes()) {
			pool.add(node.getName());
		}
		for (Representation r : panel.getRepresentations()) {
			pool.add(r.getName());
		}
		pool.add(quiver.getName());
		return pool;
	}

	public void reEvaluateNames(){
		QuiverPanel panel = getActivePanel();
		Quiver quiver = panel.quiver;
		for (Node node : quiver.getNodes()){
			node.setName();
		}
		for (Arrow arrow : quiver.getArrows()){
			arrow.setName();
		}
	}
	
	public boolean isUsedName(String name) {
		return getNamePool().contains(name);

	}
}
